#include "workflow_struct.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef NULL
#define NULL 0
#endif

//fonction de génération d'une chaine representant une variable
char * variableToString(struct variable  variable){
	char * renvoi=NULL;
	if (variable.value!=NULL){
		renvoi=malloc(strlen("Nom:")+strlen(variable.name)+strlen(",Type:")+strlen(variable.type)+strlen(",Valeur")+strlen(variable.value)+2);
		sprintf(renvoi,"Nom:%s,Type:%s,Valeur:%s\n",variable.name,variable.type,variable.value);
	}
	else{
		renvoi=malloc(strlen("Nom:")+strlen(variable.name)+strlen(",Type:")+strlen(variable.type)+2);
		sprintf(renvoi,"Nom:%s,Type:%s\n",variable.name,variable.type);
	}
	return renvoi;


}
//fonction de génération d'une chaine representant une activite
char * activiteToString(struct activity  activite){
	char * renvoi=NULL;
	char * temp=NULL;
	int i;
	int size=strlen("Id:")+strlen(activite.id);
	renvoi=malloc(size+1);
	sprintf(renvoi,"Id:%s",activite.id);
	temp=malloc(strlen(",Performer:")+strlen(activite.performer)+1);
	sprintf(temp,",Performer:%s",activite.performer);
	renvoi=realloc(renvoi,size+strlen(temp));
	memcpy(renvoi+size,temp,strlen(temp));
	size+=strlen(temp);
	free(temp);
	if (activite.description!=NULL){
		renvoi=realloc(renvoi,size+strlen(",Description:")+strlen(activite.description));
		temp=malloc(strlen(",Description:")+strlen(activite.description)+1);
		sprintf(temp,",Description:%s",activite.description);
		memcpy(renvoi+size,temp,strlen(temp));
		size+=strlen(",Description:")+strlen(activite.description);
		free(temp);
	}
	if (activite.input!=NULL){
		renvoi=realloc(renvoi,size+strlen("Input:"));
		temp=malloc(strlen(",Input:")+1);
		sprintf(temp,",Input:");
		memcpy(renvoi+size,temp,strlen(temp));
		size+=strlen(temp);
		free(temp);


		for (i=0;i<activite.nbInput;i++){
			if (i==0){
				renvoi=realloc(renvoi,size+strlen(activite.input[i]));
				temp=malloc(strlen(activite.input[i])+1);
				sprintf(temp,"%s",activite.input[i]);
				memcpy(renvoi+size,temp,strlen(temp));
				size+=strlen(activite.input[i]);
				free(temp);
			}
			else{
				renvoi=realloc(renvoi,size+strlen(activite.input[i])+1);
				temp=malloc(strlen(activite.input[i])+2);
				sprintf(temp,",%s",activite.input[i]);
				memcpy(renvoi+size,temp,strlen(temp));
				size+=strlen(activite.input[i])+1;
				free(temp);
			}
		}
	}
	if (activite.output!=NULL){
		renvoi=realloc(renvoi,size+strlen(",Output:"));
		temp=malloc(strlen(",Output:")+1);
		sprintf(temp,",Output:");
		memcpy(renvoi+size,temp,strlen(temp));
		size+=strlen(temp);
		free(temp);
		for (i=0;i<activite.nbOutput;i++){
			if (i==0){
				renvoi=realloc(renvoi,size+strlen(activite.output[i]));
				temp=malloc(strlen(activite.output[i])+1);
				sprintf(temp,"%s",activite.output[i]);
				memcpy(renvoi+size,temp,strlen(temp));
				size+=strlen(activite.output[i]);
				free(temp);
			}
			else{
				renvoi=realloc(renvoi,size+strlen(activite.output[i])+1);
				temp=malloc(strlen(activite.output[i])+2);
				sprintf(temp,",%s",activite.output[i]);
				memcpy(renvoi+size,temp,strlen(temp));
				size+=strlen(activite.output[i])+1;
				free(temp);
			}
		}
	}
	renvoi=realloc(renvoi,size+2);
	renvoi[size]='\n';
	renvoi[size+1]='\0';
	return renvoi;
}

//fonction de génération d'une chaine representant une variable en version plus petite
char * activiteToShortString(struct activity activite,int isVeryShort){
	char * message;
	int size_message=0;

	message=malloc(strlen("Activite:Nom:")+strlen(activite.name)+strlen(",id:")+strlen(activite.id)+1);
	sprintf(message,"Activite:Nom:%s,id:%s",activite.name,activite.id);
	size_message+=strlen("Activite:Nom:")+strlen(activite.name)+strlen(",id:")+strlen(activite.id);
	if (!isVeryShort){
		int size=0;
		size+=strlen(",Etat:");
		char * message2=malloc(size);
		sprintf(message2,",Etat:");
		char *state;
		int size2=0;
		if (activite.state==RUNNING){
			size2+=strlen("RUNNING\0");
			state="RUNNING\0";
		}
		else{
			if (activite.state==COMPLETED){
				size2+=strlen("COMPLETED\0");
				state="COMPLETED\0";
			}
			else{
				size2+=strlen("NOT_STARTED\0");
				state="NOT_STARTED\0";
			}
		}
		message2=realloc(message2,size+size2);
		memcpy(message2+size,state,strlen(state));
		size+=size2;
		char * temp;
		int i;
		if (activite.input!=NULL){
			message2=realloc(message2,size+strlen("Input:"));
			temp=malloc(strlen("Input:")+1);
			sprintf(temp,",Input:");
			memcpy(message2+size,temp,strlen(temp));
			size+=strlen(",Input:");
			free(temp);


			for (i=0;i<activite.nbInput;i++){
				if (i==0){
					message2=realloc(message2,size+strlen(activite.input[i]));
					temp=malloc(strlen(activite.input[i])+1);
					sprintf(temp,"%s",activite.input[i]);
					memcpy(message2+size,temp,strlen(temp));
					size+=strlen(activite.input[i]);
					free(temp);
				}
				else{
					message2=realloc(message2,size+strlen(activite.input[i])+1);
					temp=malloc(strlen(activite.input[i])+2);
					sprintf(temp,",%s",activite.input[i]);
					memcpy(message2+size,temp,strlen(temp));
					size+=strlen(activite.input[i])+1;
					free(temp);
				}
			}
		}
		if (activite.output!=NULL){
			message2=realloc(message2,size+strlen(",Output:"));
			temp=malloc(strlen(",Output:")+1);
			sprintf(temp,",Output:");
			memcpy(message2+size,temp,strlen(temp));
			size+=strlen(",Output:");
			free(temp);
			for (i=0;i<activite.nbOutput;i++){
				if (i==0){
					message2=realloc(message2,size+strlen(activite.output[i]));
					temp=malloc(strlen(activite.output[i])+1);
					sprintf(temp,"%s",activite.output[i]);
					memcpy(message2+size,temp,strlen(temp));
					size+=strlen(activite.output[i]);
					free(temp);
				}
				else{
					message2=realloc(message2,size+strlen(activite.output[i])+1);
					temp=malloc(strlen(activite.output[i])+2);
					sprintf(temp,",%s",activite.output[i]);
					memcpy(message2+size,temp,strlen(temp));
					size+=strlen(activite.output[i])+1;
					free(temp);
				}
			}
		}
		message=realloc(message,size_message+strlen(message2));
		memcpy(message+size_message,message2,strlen(message2));
		size_message+=strlen(message2);
	}
	message=realloc(message,size_message+2);
	message[size_message]='\n';
	message[size_message+1]='\0';
	return message;
}
//fonction de génération d'une chaine representant une transition
char * transitionToString(struct transition  transition){
	char * renvoi=NULL;
	int size=strlen("Id:")+strlen(transition.id)+strlen(",From:")+strlen(transition.from)+strlen(",To:")+strlen(transition.to);
	renvoi=malloc(size+1);
	sprintf(renvoi,"Id:%s,From:%s,To:%s",transition.id,transition.from,transition.to);
	if (transition.condition!=NULL){
		char * condition=malloc(strlen(",Condition:")+strlen(transition.condition)+1);
		sprintf(condition,",Condition:%s",transition.condition);
		renvoi=realloc(renvoi,size+strlen(condition));
		memcpy(renvoi+size,condition,strlen(condition));
		size+=strlen(condition);
	}
	renvoi=realloc(renvoi,size+2);
	renvoi[size]='\n';
	renvoi[size+1]='\0';
	return renvoi;
}
//retourne l'identifiant dans la table d'une activite donnee par son identifiants
int activityById(char* idActivity,struct process* process){
	if (idActivity==NULL){
		return -1;
	}
	int i=0;
	while (i<process->nbActivities && strcmp(idActivity,process->activities[i].id)!=0){
		i++;
	}
	return i;
}

//Retourne toutes les activites qui peuvent etre valider dans un processus par un utilisateur
struct activity ** findByPerformer(char* loginUser,struct process * process,int * nbActivites ){
	int i=0;
	struct activity **tableActivites=NULL;
	*nbActivites=0;
	while (i<process->nbActivities){
		if (process->activities[i].state==RUNNING){
			if (strcmp(process->activities[i].performer,loginUser)==0){
				tableActivites=realloc(tableActivites,(*nbActivites+1)*sizeof(struct activity *));
				tableActivites[*nbActivites]=&process->activities[i];
				(*nbActivites)++;
			}
		}
		i++;
	}
	return tableActivites;
}

struct transition ** findTransitionsInversees(struct process* process,struct activity activite,int * nbTransitions){
	struct transition** transitions=NULL;
	*nbTransitions=0;
	int i;
	for (i=0;i<process->nbTransitions;i++){
		if (strcmp(process->transitions[i].to,activite.id)==0){
			transitions=realloc(transitions,(*nbTransitions+1)*sizeof(struct transition *));
			transitions[*nbTransitions]=&(process->transitions[i]);
			(*nbTransitions)++;
		}
	}
	return transitions;
}

struct transition ** findTransitions(struct process* process,struct activity activite,int * nbTransitions){
	struct transition** transitions=NULL;
	*nbTransitions=0;
	int i;
	for (i=0;i<process->nbTransitions;i++){
		if (strcmp(process->transitions[i].from,activite.id)==0){
			transitions=realloc(transitions,(*nbTransitions+1)*sizeof(struct transition *));
			transitions[*nbTransitions]=&(process->transitions[i]);
			(*nbTransitions)++;
		}
	}
	return transitions;
}
struct variable * valeur(struct variable * variables,char * variableName,int nbVariables){
	int i;
	for (i=0;i<nbVariables;i++){
		if (strcmp(variables[i].name,variableName)==0){
			return &(variables[i]);
		}
	}
	return NULL;
}
int allCompleted(struct process* process,char *idActivity){
	int retour=1;
	int activity=activityById(idActivity,process);
	int nbTransitions;
	struct transition ** transitionsInversees=findTransitionsInversees(process,process->activities[activity],&nbTransitions);
	int i;
	for (i=0;i<nbTransitions;i++){
		int activity2=activityById(transitionsInversees[i]->from,process);
		if (process->activities[activity2].state!=COMPLETED){
			retour=0;
		}
	}
	free(transitionsInversees);
	return retour;
}

